package svc

import (
	"context"
	"log"
	"os/signal"
	"probe-scheduler/internal/config"
	"probe-scheduler/internal/dao"
	"probe-scheduler/internal/task"
	probePb "probe-scheduler/pb/probe"
	pb "probe-scheduler/pb/scheduler"
	"syscall"
	"time"

	"github.com/robfig/cron/v3"
	"github.com/zeromicro/go-zero/core/discov"
	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/zrpc"
)

type ServiceContext struct {
	Config      config.Config
	Scheduler   *task.Scheduler            // 任务调度器
	ProbeClient probePb.ProbeServiceClient // 探测服务客户端
	TaskDao     *dao.TaskDao               // 注入DAO层
}

// 带重试的 zrpc 客户端创建函数
func NewClientWithRetry(conf zrpc.RpcClientConf) (zrpc.Client, error) {
	retryInterval := 3 * time.Second // 重试间隔（可根据需求调整）
	retryCount := 0                  // 重试计数器

	// 监听退出信号（支持 Ctrl+C 终止程序）
	ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
	defer stop()

	for {
		select {
		case <-ctx.Done():
			// 收到退出信号，终止重试
			return nil, ctx.Err()
		default:
			retryCount++
			logx.Infof("第 %d 次尝试连接服务端: %v", retryCount, conf.Endpoints)

			// 调用 zrpc.NewClient 创建客户端（非 Must 版本，返回 error）
			client, err := zrpc.NewClient(conf)
			if err == nil {
				logx.Infof("第 %d 次尝试成功，已连接服务端", retryCount)
				return client, nil
			}
			// 连接失败，输出错误并等待重试
			logx.Infof("第 %d 次连接失败: %v，将在 %v 后重试", retryCount, err, retryInterval)
			time.Sleep(retryInterval)
		}
	}
}

func NewServiceContext(c config.Config) *ServiceContext {
	// 初始化结果通道（带缓冲避免阻塞）
	resultChan := make(chan *pb.TaskResult, 1000)

	// 添加ETCD配置的调试日志
	logx.Infof("Initializing probe service client with ETCD config - Hosts: %v, Key: %s", c.Etcd.Hosts, c.ProbeService.EtcdKey)

	// 初始化探测服务客户端（通过etcd发现服务）
	// 移除了Endpoints配置，只使用Etcd配置来避免冲突
	rpcClientConf := zrpc.RpcClientConf{
		Etcd: discov.EtcdConf{
			Hosts: c.Etcd.Hosts,
			Key:   c.ProbeService.EtcdKey,
		},
	}

	// 添加RPC客户端配置的日志
	logx.Infof("RPC Client Config: %+v", rpcClientConf)

	// client := zrpc.MustNewClient(rpcClientConf)
	client, err := NewClientWithRetry(rpcClientConf)
	if err != nil {
		logx.Errorf("Failed to initialize probe service client: %v", err)
		return nil
	}

	// 添加客户端连接状态的日志
	logx.Infof("Probe service client initialized successfully")

	probeClient := probePb.NewProbeServiceClient(client.Conn())

	// 初始化cron调度器（支持秒级调度）
	cronScheduler := cron.New(cron.WithSeconds())

	// 初始化任务调度器
	scheduler := task.NewScheduler(cronScheduler, resultChan, probeClient)
	scheduler.Start()

	// 创建任务DAO实例
	taskDao, err := dao.NewTaskDao(c.Database)
	if err != nil {
		logx.Errorf("Failed to initialize task dao: %v", err)
		return nil
	}

	// 服务启动前，从数据库加载有效任务
	loadTasksFromDB(taskDao, scheduler)

	return &ServiceContext{
		Config:      c,
		Scheduler:   scheduler,
		ProbeClient: probeClient,
		TaskDao:     taskDao,
	}
}

func loadTasksFromDB(taskDao *dao.TaskDao, scheduler *task.Scheduler) {
	// 服务启动前，从数据库加载有效任务
	ctx := context.Background()
	validTasks, err := taskDao.ListValidTasks(ctx)
	if err != nil {
		log.Fatalf("查询有效任务失败: %v", err)
	}
	log.Printf("从数据库查询到有效任务数: %d", len(validTasks))

	// 批量加载任务到调度器
	failedTasks := make([]int64, 0)
	for _, task := range validTasks {
		if _, err := scheduler.CreateTask(ctx, task); err != nil {
			log.Printf("任务加载失败: ID=%d, err=%v", task.Id, err)
			failedTasks = append(failedTasks, task.Id)
		}
	}

	// 打印加载结果
	if len(failedTasks) > 0 {
		log.Printf("部分任务加载失败，失败ID列表: %v", failedTasks)
	} else {
		log.Println("所有有效任务加载成功")
	}

}
